﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;

namespace NB_Controller_Test
{
    public interface INetLinkDataRcvProc
    {
        void OnDataRecv(byte[] data, int dataLen, IntPtr connId, Byte byType);
    }

    public class NetLink
    {
        public const int LOCAL_PORT = 65002;
        private const int DEVICE_PORT = 59876;

        /// <summary>
        /// 本地广播套接字
        /// </summary>
        Socket mSocketForBorad = null;
        List<IPEndPoint> broadIPAddrList = new List<IPEndPoint>();

        /// <summary>
        /// 数据接收回调函数队列
        /// </summary>
        List<INetLinkDataRcvProc> mDataRcvProcList = new List<INetLinkDataRcvProc>();

        /// <summary>
        /// UDPServer控制器
        /// </summary>
        public UdpServerController udpServerController { get; set; }

        private NetLink()
        {
            //InitNetLink();
        }

        private static NetLink netLink = null;
        public static NetLink GetNetLink()
        {
            if (netLink == null)
            {
                netLink = new NetLink();
            }
            return netLink;
        }

        public Boolean InitNetLink(string strIP)
        {
            //创建Socket
            mSocketForBorad = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            //设置广播包
            mSocketForBorad.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);

            //绑定套接字
            IPEndPoint endpoint = new IPEndPoint(IPAddress.Any, LOCAL_PORT);
            try
            {
                mSocketForBorad.Bind(endpoint);
            }
            catch (Exception e)
            {
                Environment.Exit(0);
            }

            //创建UdpServerController
            udpServerController = new UdpServerController();
            udpServerController.Init(this, strIP, LOCAL_PORT);

            GetBoradIPAddrList(strIP);

            return true;
        }

        public void UnInitNetLink()
        {
            try
            {
                if (mSocketForBorad != null)
                {
                    mSocketForBorad.Close();
                    mSocketForBorad = null;
                }                    

                if (udpServerController != null && udpServerController.udpServer != null)
                    udpServerController.udpServer.Stop();
            }
            catch(Exception e)
            {
                ;
            }            
        }

        private void GetBoradIPAddrList(string strIP)
        {
            broadIPAddrList.Clear();

            string hostName = Dns.GetHostName();
            IPAddress[] ips;
            ips = Dns.GetHostAddresses(hostName);

            foreach (IPAddress ip in ips)
            {
                bool ret;
                try
                {
                    ret = GlobalFun.IsRightIP(ip.ToString());                    
                }
                catch (Exception)
                {
                    continue;
                }
                if (ret)
                {
                    //判断ip是否与绑定一个网段，若是才继续否在不继续
                    string strIP3 = ip.ToString();//.Substring(ip.ToString());
                    System.Diagnostics.Debug.WriteLine("IP: " + strIP3);
                    int nIndex = strIP3.LastIndexOf(".");
                    strIP3 = strIP3.Substring(0, nIndex);
                    if (strIP.Length >= nIndex && strIP3 == strIP.Substring(0, nIndex))
                    {

                    }
                    else
                    {
                        continue;
                    }

                    //实际测试中，255.255.255.255是受限的广播（它不被路由发送，但会被送到相同物理网络段上的所有主机），容易出现问题，
                    //建议改成直接广播地址，类似“192.168.1.255”（网络广播会被路由，并会发送到专门网络上的每台主机）。
                    byte[] broadIP = ip.GetAddressBytes();
                    //Last byte to 255
                    broadIP[broadIP.Length - 1] = 255;
                    //IPAddress broadIpAddrss = new IPAddress(broadIP);
                    IPEndPoint broadIpAddr = new IPEndPoint(new IPAddress(broadIP), DEVICE_PORT);
                    //IPAddress.Broadcast
                    //IPEndPoint broadIpAddr = new IPEndPoint(IPAddress.Broadcast, DEVICE_PORT);
                    broadIPAddrList.Add(broadIpAddr);
                }
            }
        }

        public void RecvMsg(IntPtr connId, byte[] bytes)
        {
            for (int i = 0; i < mDataRcvProcList.Count; i++)
            {
                mDataRcvProcList.ElementAt(i).OnDataRecv(bytes, bytes.Length, connId, 0);
            }
        }

        public Boolean SendMsg(byte[] msgData, int offset, int msgLen, IntPtr connId)
        {
            return udpServerController.SendData(connId, msgData, msgLen); ;
        }

        public Boolean SendMsgBroadCast(byte[] msgData, int offset, int msgLen)
        {
            try
            {
                foreach (IPEndPoint targetIp in broadIPAddrList)
                {
                    //判断ip是否与绑定一个网段，若是才继续否在不继续
                    //string strIP = targetIp.Address.ToString();
                    //if(strIP)
                    //long lIP = targetIp.Port;

                    string strScanType = GlobalFun.GetAppConfigValue("ScanType");
                    
                    if (strScanType == "0")
                    {
                        IPAddress ipAddrss = null;
                        IPEndPoint ipAddr = null;

                        byte[] broadIP = targetIp.Address.GetAddressBytes();

                        string strScanStartIP = GlobalFun.GetAppConfigValue("ScanStartIP");
                        int nStartIP = GlobalFun.StringToUInt16(strScanStartIP);
                        string strScanEndIP = GlobalFun.GetAppConfigValue("ScanEndIP");
                        int nEndIP = GlobalFun.StringToUInt16(strScanEndIP);

                        GlobalFun.TaskRun(() =>
                        {
                            for (int i = nStartIP; i < nEndIP; i++)
                            {
                                broadIP[broadIP.Length - 1] = (byte)i;
                                ipAddrss = new IPAddress(broadIP);
                                ipAddr = new IPEndPoint(ipAddrss, DEVICE_PORT);
                                /*int nLen = */
                                mSocketForBorad.SendTo(msgData, offset, msgLen, SocketFlags.None, ipAddr);
                                //这里不休眠貌似会没有广播可靠
                                System.Threading.Thread.Sleep(33);
                            }
                        }
                        );
                    }
                    else
                    {
                        mSocketForBorad.SendTo(msgData, offset, msgLen, SocketFlags.None, targetIp);
                    }


                    // byte[] broadIP = targetIp.Address.GetAddressBytes();
                    //for (int i = 2; i < 254; i++)
                    //{
                    //    broadIP[broadIP.Length - 1] = (byte)i;
                    //    ipAddrss = new IPAddress(broadIP);
                    //    ipAddr = new IPEndPoint(ipAddrss, DEVICE_PORT);
                    //    /*int nLen = */mSocketForBorad.SendTo(msgData, offset, msgLen, SocketFlags.None, ipAddr);

                    //    //故意休眠下
                    //    //if(i % 10 == 0)
                    //    //{
                    //    //    Thread.Sleep(15);
                    //    //}
                    //}                    

                    //直接广播
                    ///*int nLen = */mSocketForBorad.SendTo(msgData, offset, msgLen, SocketFlags.None, targetIp);
                }
            }
            catch (Exception e)
            {
                return false;
            }
            return true;

            //如何用HPSocket实现局域网广播发送
            //return udpServerController.SendData(IntPtr.Zero, msgData, msgLen);
        }

        public Boolean SendMsgByIP(string strIP, byte[] msgData, int offset, int msgLen)
        {
            try
            {
                //foreach (IPEndPoint targetIp in broadIPAddrList)
                {
                    //IPEndPoint endPt = new IPEndPoint(new IPAddress())

                    //string iStr = "192.168.0.1:1234";
                    IPAddress IPadr = IPAddress.Parse(strIP.Split(':')[0]);//先把string类型转换成IPAddress类型
                    IPEndPoint EndPoint = new IPEndPoint(IPadr, int.Parse(strIP.Split(':')[1]));//传递IPAddress和Port

                    //EndPoint是一个抽象类，IPEndPoint继承自EndPoint。 
                    int nLen = mSocketForBorad.SendTo(msgData, offset, msgLen, SocketFlags.None, EndPoint);
                }
            }
            catch (Exception e)
            {
                return false;
            }
            return true;

            //如何用HPSocket实现局域网广播发送
            //return udpServerController.SendData(IntPtr.Zero, msgData, msgLen);
        }

        public Boolean RegisterDataRcvProc(INetLinkDataRcvProc dataRcvProc)
        {
            for (int i = 0; i < mDataRcvProcList.Count; i++)
            {
                if (mDataRcvProcList.ElementAt(i) == dataRcvProc)
                {
                    return false;
                }
            }
            //Add
            mDataRcvProcList.Add(dataRcvProc);
            return true;
        }
    }
}
